package dao

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/redis/go-redis/v9"
	"math/rand"
	__ "shop-microservices/basic/goods_proto"
	"shop-microservices/basic/inits"
	"shop-microservices/handler/models"
	"strconv"
	"time"
)

// 商品详情
func GoodsDetail(in *__.GoodsDetailReq) (*models.GoodsInfo, error) {
	var err error
	var goods models.Goods
	goodsDetail, err := goods.GetGoodsDetail(in.GoodsId)
	if err != nil {
		return nil, errors.New("获取商品详情失败")
	}
	var detail models.GoodsInfo
	key := "goodsDetail" + strconv.FormatInt(in.GoodsId, 10)
	get := inits.Rdb.Get(inits.Ctx, key).Val()
	if get == "" {
		detail = models.GoodsInfo{
			Id:          goodsDetail.Id,
			GoodsName:   goodsDetail.GoodsName,
			GoodsPrice:  goodsDetail.GoodsPrice,
			GoodsDesc:   goodsDetail.GoodsDesc,
			ImageUrl:    goodsDetail.ImageUrl,
			SliderImage: goodsDetail.SliderImage,
		}
		marshal, _ := json.Marshal(detail)
		inits.Rdb.Set(inits.Ctx, key, marshal, time.Hour)
	} else {
		_ = json.Unmarshal([]byte(get), &detail)
	}
	return &detail, err
}

// 商品详情
func ShopDetail(in *__.ShopDetailReq) (*models.ShopInfo, error) {
	var err error
	var goods models.Goods

	shopDetail, err := goods.GetShopDetail(in.GoodsId)
	if err != nil {
		return nil, errors.New("商品查询失败")
	}

	detail := models.ShopInfo{
		Id:          shopDetail.Id,
		GoodsName:   shopDetail.GoodsName,
		GoodsPrice:  shopDetail.GoodsPrice,
		GoodsDesc:   shopDetail.GoodsDesc,
		ShopName:    shopDetail.ShopName,
		ShopDesc:    shopDetail.ShopDesc,
		ShopLogo:    shopDetail.ShopLogo,
		ShopPhone:   shopDetail.ShopPhone,
		ShopAddress: shopDetail.ShopAddress,
		ShopStatus:  shopDetail.ShopStatus,
		ImageUrl:    shopDetail.ImageUrl,
		SliderImage: shopDetail.SliderImage,
	}

	return &detail, err
}

// 商品推荐
func GoodsPush(in *__.GoodsPushReq) ([]*__.GoodsPush, error) {
	var err error
	var goods models.Goods
	list, _ := goods.GoodsList()
	var goodsList []*__.GoodsPush
	for _, v := range list {
		goodsList = append(goodsList, &__.GoodsPush{
			GoodsId:     v.Id,
			GoodsName:   v.GoodsName,
			GoodsPrice:  float32(v.GoodsPrice),
			BrandName:   v.BrandName,
			GoodsUrl:    v.ImageUrl,
			SliderImage: v.SliderImage,
			Sales:       int64(v.Sales),
			GoodsDesc:   v.GoodsDesc,
		})
	}
	return goodsList, err
}

// 广告管理服务
type AdService struct {
	ads       []models.Advertisement // 广告列表
	userCache map[string]int         // 用户展示次数缓存

}

func (s *AdService) GetAdvertisementList(userId string) (models.Advertisement, error) {
	var a models.Advertisement
	list, err := a.GetAdvertisementList()
	if err != nil {
		return models.Advertisement{}, errors.New("查询广告失败" + err.Error())
	}
	if len(list) == 0 {
		return models.Advertisement{}, errors.New("无可用广告")
	}

	// 创建可用广告索引的切片，用于追踪已尝试的广告
	availableIndices := make([]int, len(list))
	for i := range availableIndices {
		availableIndices[i] = i
	}

	// 循环尝试选择广告，直到找到可用的或全部尝试完毕
	for len(availableIndices) > 0 {
		// 从剩余可用索引中随机选择一个
		idx := rand.Intn(len(availableIndices))
		selectedIdx := availableIndices[idx]
		ad := list[selectedIdx]

		// 检查用户展示次数是否超过限制
		cacheKey := fmt.Sprintf("cacheKey:%s:%v", userId, ad.Id)
		num, err := inits.InitRedis(3).Get(inits.Ctx, cacheKey).Int()
		if err != nil && err != redis.Nil {
			// 处理Redis错误，但不中断，继续尝试下一个广告
			fmt.Printf("获取广告展示次数失败: %v\n", err)
		}

		// 检查是否在限制范围内
		if num < int(ad.MaxShow) {
			// 记录展示次数
			if err := inits.InitRedis(3).Incr(inits.Ctx, cacheKey).Err(); err != nil {
				return models.Advertisement{}, errors.New("更新展示次数失败: " + err.Error())
			}
			// 设置过期时间（如果是新记录）
			if num == 0 {
				if err := inits.InitRedis(3).Expire(inits.Ctx, cacheKey, time.Hour*10).Err(); err != nil {
					fmt.Printf("设置过期时间失败: %v\n", err)
				}
			}
			return ad, nil
		}

		// 该广告已达上限，从可用索引中移除
		availableIndices = append(availableIndices[:idx], availableIndices[idx+1:]...)
	}

	// 所有广告都已达到展示限制
	return models.Advertisement{}, errors.New("所有广告已达到展示限制")
}
